#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "Action.h"
#include "ActivityGroup.h"
#include "Namespace.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Action;
class Activity;
class ActivityEdge;
class ActivityNode;
class InputPin;
class OutputPin;
class Variable;

/// <summary>
/// StructuredActivityNode
/// A StructuredActivityNode is an Action that is also an ActivityGroup and whose
/// behavior is specified by the ActivityNodes and ActivityEdges it so contains.
/// Unlike other kinds of ActivityGroup, a StructuredActivityNode owns the
/// ActivityNodes and ActivityEdges it contains, and so a node or edge can only be
/// directly contained in one StructuredActivityNode, though StructuredActivityNodes
/// may be nested.
/// </summary>
class UMLMODEL_EXPORT StructuredActivityNode : public Namespace, public Action, public ActivityGroup {

public: // Constructors and destructors
    explicit StructuredActivityNode(const QString& umlType="uml::StructuredActivityNode");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// allActions
    /// Returns this StructuredActivityNode and all Actions contained in it.
    /// </summary>
    shared_ptr<vector<Action>> allActions() const override;

    /// <summary>
    /// allOwnedNodes
    /// Returns all the ActivityNodes contained directly or indirectly within this
    /// StructuredActivityNode, in addition to the Pins of the StructuredActivityNode.
    /// </summary>
    shared_ptr<vector<ActivityNode>> allOwnedNodes() const override;

    /// <summary>
    /// sourceNodes
    /// Return those ActivityNodes contained immediately within the
    /// StructuredActivityNode that may act as sources of edges owned by the
    /// StructuredActivityNode.
    /// </summary>
    virtual shared_ptr<vector<ActivityNode>> sourceNodes() const;

    /// <summary>
    /// targetNodes
    /// Return those ActivityNodes contained immediately within the
    /// StructuredActivityNode that may act as targets of edges owned by the
    /// StructuredActivityNode.
    /// </summary>
    virtual shared_ptr<vector<ActivityNode>> targetNodes() const;

    /// <summary>
    /// containingActivity
    /// The Activity that directly or indirectly contains this StructuredActivityNode
    /// (considered as an Action).
    /// </summary>
    shared_ptr<Activity> containingActivity() const override;

public: // Properties
    /// <summary>
    /// activity getter
    /// The Activity immediately containing the StructuredActivityNode, if it is not
    /// contained in another StructuredActivityNode.
    /// </summary>
    shared_ptr<Activity> activity() const;

    /// <summary>
    /// activity setter
    /// The Activity immediately containing the StructuredActivityNode, if it is not
    /// contained in another StructuredActivityNode.
    /// </summary>
    void setActivity(shared_ptr<Activity> value);

    /// <summary>
    /// edges getter
    /// The ActivityEdges immediately contained in the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<ActivityEdge>>& edges();

    /// <summary>
    /// mustIsolate getter
    /// If true, then any object used by an Action within the StructuredActivityNode
    /// cannot be accessed by any Action outside the node until the
    /// StructuredActivityNode as a whole completes. Any concurrent Actions that would
    /// result in accessing such objects are required to have their execution deferred
    /// until the completion of the StructuredActivityNode.
    /// 
    /// </summary>
    bool mustIsolate() const;

    /// <summary>
    /// mustIsolate setter
    /// If true, then any object used by an Action within the StructuredActivityNode
    /// cannot be accessed by any Action outside the node until the
    /// StructuredActivityNode as a whole completes. Any concurrent Actions that would
    /// result in accessing such objects are required to have their execution deferred
    /// until the completion of the StructuredActivityNode.
    /// 
    /// </summary>
    void setMustIsolate(bool value);

    /// <summary>
    /// nodes getter
    /// The ActivityNodes immediately contained in the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<ActivityNode>>& nodes();

    /// <summary>
    /// structuredNodeInputs getter
    /// The InputPins owned by the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<InputPin>>& structuredNodeInputs();

    /// <summary>
    /// structuredNodeOutputs getter
    /// The OutputPins owned by the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<OutputPin>>& structuredNodeOutputs();

    /// <summary>
    /// variables getter
    /// The Variables defined in the scope of the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<Variable>>& variables();

private: // Fields
    /// <summary>
    /// activity
    /// The Activity immediately containing the StructuredActivityNode, if it is not
    /// contained in another StructuredActivityNode.
    /// </summary>
    shared_ptr<Activity> activity_;

    /// <summary>
    /// edges
    /// The ActivityEdges immediately contained in the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<ActivityEdge>> edges_;

    /// <summary>
    /// mustIsolate
    /// If true, then any object used by an Action within the StructuredActivityNode
    /// cannot be accessed by any Action outside the node until the
    /// StructuredActivityNode as a whole completes. Any concurrent Actions that would
    /// result in accessing such objects are required to have their execution deferred
    /// until the completion of the StructuredActivityNode.
    /// 
    /// </summary>
    const static bool mustIsolate_default_;
    bool mustIsolate_= mustIsolate_default_;

    /// <summary>
    /// nodes
    /// The ActivityNodes immediately contained in the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<ActivityNode>> nodes_;

    /// <summary>
    /// structuredNodeInputs
    /// The InputPins owned by the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<InputPin>> structuredNodeInputs_;

    /// <summary>
    /// structuredNodeOutputs
    /// The OutputPins owned by the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<OutputPin>> structuredNodeOutputs_;

    /// <summary>
    /// variables
    /// The Variables defined in the scope of the StructuredActivityNode.
    /// </summary>
    vector<shared_ptr<Variable>> variables_;

};

} // namespace uml
